#pragma once

#include <map>
#include <list>
#include "Singleton.h"
#include "Pointer.h"
#include "Entity.h"
#include "HashedString.h"
#include "CameraNode.h"
#include "System.h"
#include "EntityController.h"
#include "World.h"

#define Game	GameApplication::getSingleton()

class GameApplication : public Singleton<GameApplication>
{
public:
	// Entity Manipulation
	bool CreateEntity( HashedString avatarName );
	bool CreateEntity( HashedString avatarName, Pointer<Entity>& entity );
	bool CreateEntity( HashedString avatarName, HashedString entityName );
	bool CreateEntity( HashedString avatarName, HashedString entityName, Pointer<Entity>& entity );
	void RetreiveEntity( HashedString entityName, Pointer<Entity>& entity );
	void RemoveEntity( HashedString entityName );
	void CreateController( HashedString entityName );
	void CreateController( HashedString entityName, Pointer<EntityController>& controller );
	void RetreiveController( HashedString entityName, Pointer<EntityController>& controller );
	void RemoveController( HashedString entityName );
	void RemoveController( EntityController* controller );
	void RemoveController( Entity* entity );
	void SetEntitySelectable( HashedString entityName );
	void SetEntityUnselectable( HashedString entityName );
	void SetEntityGroup( HashedString groupName, HashedString entityName );
	void RemoveEntityFromAllGroups( HashedString entityName );
	void AddEntityToPathingWorld( HashedString worldName, HashedString entityName );
	void RemoventityFromPathingWorld( HashedString worldName, HashedString entityName );
	void AddEntityToSimulationWorld( HashedString worldName, HashedString entityName );
	void RemoveEntityFromSimulationWorld( HashedString worldName, HashedString entityName );
	
	// Pathing
	void CreatePathingWorld( HashedString worldName );
	void CreatePathingWorld( HashedString worldName, Pointer<Pathing::World>& world );
	void RetreivePathingWorld( HashedString worldName, Pointer<Pathing::World>& world );
	
	// Simulations
	void CreateSimulationWorld( HashedString worldName );
	void CreateSimulationWorld( HashedString worldName, Pointer<Pathing::World>& world );
	void RetreiveSimulationWorld( HashedString worldName, Pointer<Pathing::World>& world );

	// SceneGraph
	void RememberNode( HashedString nodeName, Pointer<INode> node );
	void RetreiveNode( HashedString nodeName, Pointer<INode>& node );
	void ForgetNode( HashedString nodeName );

	// Utility
	Entity* Select( int x, int y );
	Entity* Select( int x, int y, Maths::Vector3D& point );
		
	// System functions - avoid use
	Entity::Map_t& _getAllEntities();
	Pointer<System>& _getSelectables();
	std::vector<std::string>& _getTextureStrings();
	EntityController::Vector_t& _getControllers();
	Pathing::World::Map_t& _getWorlds();
	Pointer<CameraNode>& _getMainCamera();
protected:
	// Camera Link
	Pointer<CameraNode> m_mainCamera;
	// Master Lists
	std::map<HashedString, std::list<Entity*>> m_entityGroups;
	// selectable system; used for raycast from pointer
	Pointer<System> m_selectables;
	// list of all controllers
	EntityController::Vector_t m_controllers;
	// list of textures
	std::vector<std::string> m_textureStrings;
	// list of all entities, by name
	Entity::Map_t m_entities;
	// Worlds - containers of obstacles, by name
	Pathing::World::Map_t m_worlds;

	INode::Map_t m_nodesNames;
};